/**  
 * @Title: FlowTaskService.java
 * @Description: TODO(描述)
 * @author liuyi
 * @date 2023-09-12 13:40:59 
 */  
package com.fsxgt.datagrid.executor.service;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSON;
import com.fsxgt.datagrid.core.component.HttpComponent;
import com.fsxgt.datagrid.core.exception.DataGridException;
import com.fsxgt.datagrid.core.task.TaskRunParam;
import com.fsxgt.datagrid.core.task.SubTask;
import com.fsxgt.datagrid.core.task.Task;
import com.fsxgt.datagrid.core.task.TaskCallback;
import com.fsxgt.datagrid.core.task.TaskContainer;
import com.fsxgt.datagrid.core.task.TaskContext;
import com.fsxgt.datagrid.core.utils.LogHelpper;
import com.fsxgt.datagrid.core.utils.ReturnT;
import com.fsxgt.datagrid.ds.utils.ParamUtil;
import com.fsxgt.datagrid.flow.bo.FlowComponentBO;
import com.fsxgt.datagrid.flow.bo.FlowInfoBO;
import com.fsxgt.datagrid.flow.bo.FlowRelationBO;
import com.fsxgt.datagrid.flow.handler.FlowContext;
import com.fsxgt.datagrid.flow.handler.FlowReturn;
import com.fsxgt.datagrid.flow.handler.IComponentHandler;
import com.fsxgt.datagrid.flow.service.impl.CmpRegistryService;
import com.fsxgt.datagrid.flow.service.impl.FlowService;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**  
 * @ClassName: FlowTaskService
 * @Description: TODO(描述)
 * @author liuyi
 * @date 2023-09-12 13:40:59 
*/
@Slf4j
@Service
public class FlowTaskService {



	@Autowired
	private FlowService flowService;
	
	@Autowired
	private CmpRegistryService cmpRegistryService;
	

	
	@Autowired
	private HttpComponent httpComponent;

	@Value("${console.address}")
	private String console;
	
	@Value("${executor.main.thread.threadSize}")
	private int threadSize;
	
	private TaskContainer taskContainer;


	@PostConstruct
	private void init() {
		taskContainer=taskContainer.getInstance(threadSize);
	}

	
	
	@Data
	private class FlowTask extends Task{

		private FlowInfoBO flowInfoBO;
		private String version;
		
		public FlowTask(String id,FlowInfoBO flowInfoBO,String version) {
			super(id,flowInfoBO.getName());
			this.flowInfoBO=flowInfoBO;
			this.version=version;
		}
		
	}
	
	private Map<String, FlowTask> cacheMap = new ConcurrentHashMap();
	
	public Task getTask(String flowId,String version) throws DataGridException {
		FlowTask flowTask=null;

		if (version != null && cacheMap.containsKey(flowId)&&cacheMap.get(flowId).getVersion()!=null
				&& cacheMap.get(flowId).getVersion().equals(version)) {
			// 使用缓存
			flowTask=cacheMap.get(flowId);
		} else {
			FlowInfoBO flowInfoBO = flowService.getFlowAndConfig(flowId);
			
			flowTask=new FlowTask(flowInfoBO.getId(),flowInfoBO,version);
			 
			
			for(FlowComponentBO bo:flowInfoBO.getComponents()) {
				
				IComponentHandler handler = cmpRegistryService.getHandler(bo.getComponentType());


				flowTask.addSubTask(new SubTask(bo.getComponentSeq(),bo.getName()) {
					@Override
					public FlowReturn handler(TaskContext context) throws Exception {
						// TODO Auto-generated method stub
						return handler.handler(bo.getConfig(),(FlowContext) context);
					}

					@Override
					public void stopHandler(TaskContext context) throws Exception{
						// TODO Auto-generated method stub
						handler.stopHandler(bo.getConfig(),(FlowContext) context);
					}
				});
			}
			

			for (FlowRelationBO relation : flowInfoBO.getRelations()) {
				flowTask.addChildSubTask(relation.getCmpFrom(),flowTask.getSubTask(relation.getCmpTo()));
			}
			
			cacheMap.put(flowId, flowTask);
		}
		return flowTask;
		
	}
	
	public static FlowContext getContext() {
		
		Map params = new ConcurrentHashMap();

		Calendar cur = Calendar.getInstance();

		params.put("curDateTime", new Timestamp(cur.getTime().getTime()));// 当前时间

		cur.set(Calendar.SECOND, 0);
		cur.set(Calendar.MILLISECOND, 0);

		params.put("curMinute", new Timestamp(cur.getTime().getTime()));// 当前分钟

		if (cur.get(Calendar.MINUTE) >= 30) {
			cur.set(Calendar.MINUTE, 30);
		} else {
			cur.set(Calendar.MINUTE, 0);
		}
		
		params.put("curMinute30", new Timestamp(cur.getTime().getTime()));// 当前半小时
		

		cur.set(Calendar.MINUTE, 0);
		params.put("curHour", new Timestamp(cur.getTime().getTime()));// 当前小时
		

		cur.set(Calendar.HOUR, 0);
		cur.set(Calendar.MINUTE, 0);

		params.put("curDay", new Timestamp(cur.getTime().getTime()));// 当天
		
		FlowContext flowContext=new FlowContext();
		

		flowContext.put(ParamUtil.PARAM_KEY, params);
		
		return flowContext;
		
	}
	
	public String execute(String flowId, Date logDate, String execId, String version,Integer threads,Integer timeout,Integer retryCount,Map context1) throws DataGridException {
		
		
		Task task=getTask(flowId, version);
		FlowContext context=getContext();
		
		Map p=(Map) context.get(ParamUtil.PARAM_KEY);
		
		if(context1!=null) {
			context1.forEach((k,v)->{
				p.put(k.toString(), v);
			});
		}
		

		
		String logFileName = LogHelpper.makeLogFileName(logDate, execId);
		
		
		TaskRunParam param=new TaskRunParam(execId,logFileName,threads,timeout,retryCount);
		
		taskContainer.execute(task,context,param, new TaskCallback() {

			@Override
			public void handler(Date startTime, Date overTime, String status, String logPath, String execId) {
				// TODO Auto-generated method stub
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

				Map param = new HashMap();
				param.put("overTime", format.format(overTime));
				param.put("startTime", format.format(startTime));
				param.put("status", status);
				param.put("logPath", logPath);
				param.put("execId", execId);
				param.put("objType", "1");
				param.put("objId", flowId);

				log.info("callback:" + "http://" + console + "/executor/callback");
				log.info("callback:" + JSON.toJSONString(param));

				ReturnT<Map> result = httpComponent.sendHttpPostRetry("http://" + console + "/executor/callback", param,
						ReturnT.class);
			}
			
		});
		
		
		
		return execId;
	}

	/**  
	 * @Title: interrupted
	 * @Description: TODO(描述)
	 * @param string
	 * @author liuyi
	 * @date 2023-09-12 15:17:19 
	 */  
	public void interrupted(String execId) {
		// TODO Auto-generated method stub
		taskContainer.interrupted(execId);
	}
	
	
}
